#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>

#define SAMPLE_RATE 44100    // 采样率（需与 PCM 数据匹配）
#define FORMAT paFloat16     // PCM 格式（如 paInt16、paFloat32）
#define CHANNELS 2           // 声道数
#define FRAMES_PER_BUFFER 512// 每帧缓冲区大小


// 回调函数：实时填充音频数据到输出缓冲区
static int playCallback(const void* input, void* output,
                        unsigned long frameCount,
                        const PaStreamCallbackTimeInfo* timeInfo,
                        PaStreamCallbackFlags statusFlags,
                        void* userData) {
    AudioState* state = (AudioState*)userData;
    float* out = (float*)output;
    int framesToCopy = frameCount;

    // 计算剩余可播放的帧数
    int remainingFrames = state->totalFrames - state->currentFrame;
    if (remainingFrames < framesToCopy) {
        framesToCopy = remainingFrames;
    }

    // 复制 PCM 数据到输出缓冲区
    for (int i = 0; i < framesToCopy * CHANNELS; i++) {
        *out++ = state->pcmData[state->currentFrame * CHANNELS + i];
    }

    // 更新播放位置
    state->currentFrame += framesToCopy;

    // 判断是否播放完成
    return (state->currentFrame >= state->totalFrames) ? paComplete : paContinue;
}


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_vdVideoDecode.globalInit();
    m_playImage = this->findChild<FrameOpenGLWidget *>("widget");
    connect(this, SIGNAL(sgnUpdateFrameFormat(int)), this, SLOT(sltUpdateFrameFormat(int)), Qt::BlockingQueuedConnection);
    connect(this, &MainWindow::sgnUpdateAudioFrame, this, &MainWindow::sltUpdateAudioFrame);

    PaError err;
    //初始化 PortAudio
    err = Pa_Initialize();
   if (err != paNoError)
   {
       qDebug()<<"Pa_Initialize fail.";
   }
   m_bFirstOpenAudioDevice = false;
}

MainWindow::~MainWindow()
{
    delete ui;
    m_vdVideoDecode.globalUnInit();
    Pa_Terminate();
}

void  MainWindow::sltUpdateFrameFormat(int nFormatType)
{
    if(m_vdVideoDecode.isClose())
        return;

    m_playImage->setFrameDataFormat((FrameDataFormat)nFormatType);
}

void MainWindow::sltUpdateAudioFrame(const QByteArray &data)
{
    PaError err = Pa_WriteStream(m_stream, data.data(), data.size());
    if(err != paNoError)
    {
        qDebug()<<"写入音频数据失败: " << Pa_GetErrorText(err);
    }
}

void MainWindow::on_pushButtonOpenFile_clicked(bool checked)
{
    bool bIsSupportHardware = ui->checkBoxHW->checkState() == Qt::Checked ? true:false;
    QString filename = QFileDialog::getOpenFileName(nullptr, "Open Video File");
   if (!filename.isEmpty())
    {
       m_vdVideoDecode.setHWDecoder(bIsSupportHardware);
       m_vdVideoDecode.setStreamDecodeCallback([](int nStreamType, int nFormatType, long long llDecodeTs, long long llPlayTs, int width, int height, unsigned char ** pStreamData, int * linesize, void * pUserData){
           MainWindow *pMainWindow = (MainWindow *)pUserData;
           if(nFormatType !=  pMainWindow->m_playImage->getFrameDataFormat())
           {
               //发送信号出去，更新opengl初始化纹理。（因为opengl初始化纹理是非线程安全的，需要在UI或同FrameOpenGLWidget线程中处理。）
               emit pMainWindow->sgnUpdateFrameFormat(nFormatType);
           }

           pMainWindow->m_playImage->updateFrame(nFormatType, pStreamData, linesize, width, height);
       },
       [](int nSampleRate, int nChannel, int nSampleFmt, uint64_t nChannelLaytout, unsigned char *pStreamData, int nStreamDataLength, void * pUserData){
           MainWindow *pMainWindow = (MainWindow *)pUserData;
           if(!pMainWindow->m_bFirstOpenAudioDevice)
           {
               /*
               //打开音频流
              PaError err = Pa_OpenDefaultStream(&pMainWindow->m_stream,
                                              0,          // 无输入
                                              CHANNELS, // 输出通道数
                                              paInt16,  // 32位浮点格式
                                              SAMPLE_RATE,
                                              FRAMES_PER_BUFFER,
                                              NULL,       // 无回调
                                              NULL);
              if (err != paNoError)
              {
                  qDebug()<<"Pa_OpenStream fail.";
              }

              //启动音频流
              err = Pa_StartStream(pMainWindow->m_stream);
              if (err != paNoError)
              {
                  qDebug()<<"Pa_StartStream fail.";
              }
              */

               //打开音频流
               PaStreamParameters outputParams;
               outputParams.device = Pa_GetDefaultOutputDevice(); // 使用默认输出设备
               if(AV_CH_LAYOUT_STEREO == nChannel)
               {
                   outputParams.channelCount = 2;
               }
               else
               {
                   outputParams.channelCount = 1;
               }
               switch (nSampleFmt) {
               case AV_SAMPLE_FMT_U8:
                   outputParams.sampleFormat = paUInt8;
                   break;

               case AV_SAMPLE_FMT_S16:
                    outputParams.sampleFormat = paInt16;
                   break;

               case AV_SAMPLE_FMT_S32:
                    outputParams.sampleFormat = paInt32;
                   break;

               case AV_SAMPLE_FMT_FLT:
                    outputParams.sampleFormat = paFloat32;
                   break;

               case AV_SAMPLE_FMT_U8P:
                   outputParams.sampleFormat = paUInt8 | paNonInterleaved;
                   break;

               case AV_SAMPLE_FMT_S16P:
                    outputParams.sampleFormat = paInt16 | paNonInterleaved;
                   break;

               case AV_SAMPLE_FMT_S32P:
                    outputParams.sampleFormat = paInt32 | paNonInterleaved;
                   break;

               case AV_SAMPLE_FMT_FLTP:
                    outputParams.sampleFormat = paFloat32 | paNonInterleaved;
                   break;

               default:
                    outputParams.sampleFormat = paFloat32;
                   break;
               }
               outputParams.suggestedLatency = Pa_GetDeviceInfo(outputParams.device)->defaultLowOutputLatency;
               outputParams.hostApiSpecificStreamInfo = NULL;

                PaError err = Pa_OpenStream(&pMainWindow->m_stream, NULL, &outputParams,
                                       nSampleRate, nStreamDataLength/outputParams.channelCount > 0 ? nStreamDataLength/outputParams.channelCount : FRAMES_PER_BUFFER,
                                       paNoFlag, NULL, NULL);
                if (err != paNoError)
                {
                    qDebug()<<"Pa_OpenStream fail.";
                }

                //启动音频流
                err = Pa_StartStream(pMainWindow->m_stream);
                if (err != paNoError)
                {
                    qDebug()<<"Pa_StartStream fail.";
                }

                pMainWindow->m_bFirstOpenAudioDevice = true;
           }


           int framesRemaining = nStreamDataLength;
           const int16_t *pcmPtr = (int16_t *)pStreamData; // 假设是16位PCM数据

           while(framesRemaining > 0)
           {
               int framesToWrite = (framesRemaining > FRAMES_PER_BUFFER) ?
                                  FRAMES_PER_BUFFER : framesRemaining;

               PaError err = Pa_WriteStream(pMainWindow->m_stream, pcmPtr, framesToWrite);
               if(err != paNoError)
               {
                   qDebug()<<"写入音频数据失败: " << Pa_GetErrorText(err);
                   break;
               }

               pcmPtr += framesToWrite * CHANNELS; // 移动指针
               framesRemaining -= framesToWrite;
           }


       },this);
       m_vdVideoDecode.setFileStatusCallback([](int FileStatus, int nErrorCode, void * pUserData){
            qDebug()<<"file is end";
       },this);

       m_vdVideoDecode.open(filename);
    }
}

void MainWindow::on_pushButtonCloseFile_clicked()
{
    if(m_stream != nullptr)
    {
        //清理资源
        Pa_StopStream(m_stream);
        Pa_CloseStream(m_stream);
        m_bFirstOpenAudioDevice = false;
        m_stream = nullptr;
    }

    m_vdVideoDecode.close();
}

void MainWindow::on_pushButtonPauseFile_clicked()
{
    m_vdVideoDecode.setPause(!m_vdVideoDecode.isPause());
}
